package cn.kilo.domain.model.pay.req;

import cn.hutool.core.util.RandomUtil;
import cn.kilo.domain.support.WeChatPayConfig;
import com.wechat.pay.contrib.apache.httpclient.util.PemUtil;
import lombok.extern.slf4j.Slf4j;
import okhttp3.HttpUrl;
import org.apache.http.HttpEntity;
import org.apache.http.HttpStatus;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.*;
import java.util.Base64;

/**
 * @author kilok
 * 封装公共请求api，在业务统一处理
 */

@Component
@Slf4j
public class WeChatPayRequest {

    @Resource
    private CloseableHttpClient wxPayClient;

    @Resource
    private WeChatPayConfig weChatPayConfig;

    public String weChatHttpGet(String url){
        try{
            //拼接请求参数
            HttpGet httpGet=new HttpGet(url);
            httpGet.setHeader("Accept","application/json");

            //完成签名并执行请求
            CloseableHttpResponse response=wxPayClient.execute(httpGet);

            return getResponseBody(response);

        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }

    /**
     * post请求
     * @param url url
     * @param paramStr 请求参数
     * @return 请求返回的响应体
     */
    public String weChatHttpPost(String url,String paramStr){
        try{
            String s="WECHATPAY2-SHA256-RSA2048 ";
            HttpPost httpPost=new HttpPost(url);
            HttpUrl httpUrl=HttpUrl.parse(url);
            StringEntity entity=new StringEntity(paramStr, ContentType.APPLICATION_JSON);

            entity.setContentType("application/json");

            httpPost.setEntity(entity);
            httpPost.setHeader("Accept","application/json");
            httpPost.setHeader("Authorization",s+buildRequestBody(paramStr,httpUrl));
            httpPost.setHeader("Content-Type","application/json");
            String method = httpPost.getMethod();
            log.info("method:{}",method);
            HttpEntity entity1 = httpPost.getEntity();
            log.info("entity:{}",entity1);
            CloseableHttpResponse response = wxPayClient.execute(httpPost);
            return getResponseBody(response);
        }catch (Exception e){
            throw new RuntimeException(e.getMessage());
        }
    }

    private String buildRequestBody(String params,HttpUrl url) throws UnsupportedEncodingException {
        String nonceStr= RandomUtil.randomString(10);
        long timeStamp= System.currentTimeMillis()/1000;
        String message=buildMessage("POST",url,timeStamp,nonceStr,params);
        return "mchid=\"" + weChatPayConfig.getMCH_ID() + "\","
                + "nonce_str=\"" + nonceStr + "\","
                + "timestamp=\"" + timeStamp+ "\","
                + "serial_no=\"" + weChatPayConfig.getMCH_SERIAL_NO() + "\","
                + "signature=\"" + getSign(message.getBytes("utf-8")) + "\"";
    }

    public String getSign(byte[] message){
        try {
            Signature sign=Signature.getInstance("SHA256withRSA");
            PrivateKey privateKey= PemUtil.loadPrivateKey(weChatPayConfig.getPrivateKeyPath());
            sign.initSign(privateKey);
            sign.update(message);
            return Base64.getEncoder().encodeToString(sign.sign());
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            throw new RuntimeException(e);
        }
    }

    public String getSign(){
        try {
            Signature sign=Signature.getInstance("SHA256withRSA");
            PrivateKey privateKey= PemUtil.loadPrivateKey(weChatPayConfig.getPrivateKeyPath());
            sign.initSign(privateKey);
            return Base64.getEncoder().encodeToString(sign.sign());
        } catch (NoSuchAlgorithmException | InvalidKeyException | SignatureException e) {
            throw new RuntimeException(e);
        }
    }

    private String buildMessage(String method,HttpUrl url,long timestamp,String nonceStr,String body){
        String canonicalUrl=url.encodedPath();
        if (url.encodedQuery() != null) {
            canonicalUrl += "?" + url.encodedQuery();
        }
        return method + "\n"
                + canonicalUrl + "\n"
                + timestamp + "\n"
                + nonceStr + "\n"
                + body + "\n";
    }
    /**
     * 获取请求返回的响应体
     * @param response
     * @return
     * @throws IOException
     */
    private String getResponseBody(CloseableHttpResponse response) throws IOException {

        //获取响应体
        HttpEntity entity=response.getEntity();

        String body= null==entity?"":EntityUtils.toString(entity);

        //响应状态码
        int statusCode=response.getStatusLine().getStatusCode();

        //处理成功 返回204（关闭订单时微信支付返回正常的状态码）
        if(HttpStatus.SC_OK==statusCode||HttpStatus.SC_NO_CONTENT==statusCode){
            log.info("支付成功，返回结果={}",body);
        }else{
            String msg="微信支付请求失败，响应码"+statusCode+",返回结果:{}"+body;
            log.error(msg);
            throw new RuntimeException(msg);
        }
        return body;
    }
}
